<?php 
require_once MODULE_PATH.'/websvc/lib/WebsvcService.php';
class cloudService extends  WebsvcService
{
	protected $m_ServerDO 	= "appcloudcontrol.server.do.ServerSystemDO"; //this do has no perm control
	protected $m_CmdQueueDO = "appcloudcontrol.command.do.CommandQueueSystemDO";
	protected $m_InstanceDO = "appcloudcontrol.instance.do.InstanceSystemDO";
	
	protected $m_CurrentServerId;
	protected $m_CurrentServerReponseKey;
	
	const NUM_OF_CMD_ON_EACH_REQUEST = 10;
	const CMD_STATUS_PENDING 		= 'pending';
	const CMD_STATUS_PROCESSING 	= 'processing';
	const CMD_STATUS_PROCESSED	 	= 'processed';
	
	public function getCommands()
	{		
		if(!$this->_validateRequest())
		{
			return false;
		}		
		$serverId = $this->m_CurrentServerId;
		$searchRule = "[server_id] = '$serverId' AND [status]='".self::CMD_STATUS_PENDING."' ";
		$sortRule = "[Id] ASC"; //FIFO 
		$result=BizSystem::getObject($this->m_CmdQueueDO)->directfetch($searchRule,self::NUM_OF_CMD_ON_EACH_REQUEST,0,$sortRule)->toArray();
		$commandSet = array();
		foreach($result as $record)
		{
			$command = array(
				"Id" 		=> $record['Id'],
				"command" 	=> $record['command'],
				"parameter" => $record['parameter']
			);
			$ids .= "'".$record['Id']."',";
			$commandSet[] = $command;
		}		
		//update command queue status				
		if(count($commandSet)){
			$ids = substr($ids,0,strlen($ids)-1);
			$searchRule = "[Id] IN ($ids)";
			$now = date('Y-m-d H:i:s');		
			BizSystem::getObject($this->m_CmdQueueDO)->updateRecords("[status]='".self::CMD_STATUS_PROCESSING."',[execute_start_time]='$now'",$searchRule);
		}
		return $commandSet;
	}
	
	public function resetCommands()
	{
		if(!$this->_validateRequest())
		{
			return false;
		}		
		$serverId = $this->m_CurrentServerId;
		$searchRule = "[server_id] = '$serverId' AND [status]!='".self::CMD_STATUS_PENDING."' ";
		$searchRule = "[server_id] = '$serverId' ";
		BizSystem::getObject($this->m_CmdQueueDO)->updateRecords("[status]='pending',[execute_start_time]='',[execute_during]=0,[execute_result]=NULL ",$searchRule);
		
	}
	
	public function updateCommandStatus()
	{
		if(!$this->_validateRequest())
		{
			return false;
		}		
		$serverId = $this->m_CurrentServerId;
		$args = json_decode($_REQUEST['argsJson']);
		$cmdId = $args->cmd_id;
		$result = $args->result;
		$searchRule = "[server_id] = '$serverId' AND [Id]='$cmdId' ";
		$cmdRec = BizSystem::getObject($this->m_CmdQueueDO)->fetchOne($searchRule);
		$cmdRec['execute_result'] = $result;
		$cmdRec['execute_end_time'] = date('Y-m-d H:i:s');
		$execute_during = strtotime($cmdRec['execute_end_time']) - strtotime($cmdRec['execute_start_time']);
		$cmdRec['execute_during'] = $execute_during;
		$cmdRec['status'] = self::CMD_STATUS_PROCESSED;
		
		if($cmdRec['callback']) //process callback when execute finished 
		{
			$callback = $cmdRec['callback'];
			if($cmdRec['callback_parameter'])
			{
				$callback_parameter = unserialize($cmdRec['callback_parameter']);
			}
			else
			{
				$callback_parameter = array();
			}
			$this->_processCallback($callback,$callback_parameter);
		}
		$cmdRec->save();
		return true;
	}

	public function notifyInstanceCreated()
	{
		if(!$this->_validateRequest())
		{
			return false;
		}		
		$serverId = $this->m_CurrentServerId;
		$args = json_decode($_REQUEST['argsJson']);
		$hostname 	= $args->hostname;
		$domain 	= $args->domain;
		$dbname 	= $args->dbname;
		$dbuser 	= $args->dbuser;
		$dbpasswd 	= $args->dbpasswd;
		$start_time	= $args->start_time;
		$end_time	= $args->end_time;
		$foreign_key= $args->foreign_key;
		$status		= $args->status;
		$instanceRecord=array(
			"server_id" 	=> $serverId,
			"foreign_key" 	=> $foreign_key,
			"hostname"		=> $hostname,
			"domain"		=> $domain,
			"dbname"		=> $dbname,
			"dbuser"		=> $dbuser,
			"dbpass"		=> $dbpasswd,
			"start_time"	=> $start_time,
			"end_time"		=> $end_time,
			"status"		=> $status,
			"time_usage"	=> 0,
			"storage_usage"	=> 0,
			"traffic_usage"	=> 0
		);
		$do = BizSystem::getObject($this->m_InstanceDO);
		$testRec = $do->fetchOne("[foreign_key]='$foreign_key'");
		if($testRec)
		{
			foreach($instanceRecord as $k=>$v)
			{
				$testRec[$k] = $v;
			}
			$testRec->save();
		}
		else
		{
			$do->insertRecord($instanceRecord);
		}
		$this->updateServerInstanceCounter();
		return true;
	}
	
	public function notifyInstanceStatusChanged()
	{
		if(!$this->_validateRequest())
		{
			return false;
		}		
		$serverId = $this->m_CurrentServerId;
		$args = json_decode($_REQUEST['argsJson']);
		$hostname 	= $args->hostname;
		$domain 	= $args->domain;		
		$foreign_key= $args->foreign_key;
		$status		= $args->status;
		$alias		= $args->alias;
		$do = BizSystem::getObject($this->m_InstanceDO);
		$testRec = $do->fetchOne("[foreign_key]='$foreign_key' AND [hostname]='$hostname' AND [domain]='$domain'");
		if($testRec)
		{
			if($status)
			{
				$testRec['status'] = $status;
			}
			
			if($alias)
			{
				$testRec['alias'] = $alias;
			}
			
			$testRec->save();
		}
		return true;		
	}
	
	public function notifyInstanceUsageUpdated()
	{		
		if(!$this->_validateRequest())
		{
			return false;
		}		
		$serverId = $this->m_CurrentServerId;
		$args = json_decode($_REQUEST['argsJson']);
		$hostname 	= $args->hostname;
		$domain 	= $args->domain;		
		$foreign_key= $args->foreign_key;
		$storage_usage	= $args->storage_usage;
		$database_usage	= $args->database_usage;
		$backup_usage	= $args->backup_usage;
		$log_usage		= $args->log_usage;
		$do = BizSystem::getObject($this->m_InstanceDO);
		$testRec = $do->fetchOne("[foreign_key]='$foreign_key' AND [hostname]='$hostname' AND [domain]='$domain'");
		if($testRec)
		{
			$testRec['storage_usage'] 	= $storage_usage;
			$testRec['database_usage'] 	= $database_usage;
			$testRec['backup_usage'] 	= $backup_usage;
			$testRec['log_usage'] 		= $log_usage;
			$testRec->save();
		}
		return true;	
	}
	
	public function notifyInstanceDestroyed()
	{
		if(!$this->_validateRequest())
		{
			return false;
		}		
		$serverId = $this->m_CurrentServerId;
		$args = json_decode($_REQUEST['argsJson']);
		$hostname 	= $args->hostname;
		$domain 	= $args->domain;		
		$foreign_key= $args->foreign_key;
		$do = BizSystem::getObject($this->m_InstanceDO);
		$testRec = $do->fetchOne("[foreign_key]='$foreign_key' AND [hostname]='$hostname' AND [domain]='$domain'");
		if($testRec)
		{
			$testRec->delete();
		}
		//update servers instances count
		$this->updateServerInstanceCounter();
		return true;		
	}	
	
	public function updateServerInstanceCounter()
	{
		if(!$this->_validateRequest())
		{
			return false;
		}
		$serverId = $this->m_CurrentServerId;
		$searchRule = "[server_id]='$serverId'";
		$instances = BizSystem::getObject($this->m_InstanceDO)->directfetch($searchRule);
		$currentInstance = $instances->count();
		
		$serverRec = BizSystem::getObject($this->m_ServerDO)->fetchById($serverId);
		$serverRec['current_instance']=$currentInstance;
		$serverRec->save();
		return true;
	}
	
	protected function output($response=null, $format='xml')
    {    	
    	return parent::output($response, $format, $this->m_CurrentServerReponseKey);
    }
	
	protected function _processCallback($callback,$parameter=array())
	{
		$cmdArr = explode("::", $callback);
		$svc = $cmdArr[0];
		$method = $cmdArr[1];
		$svcObj = BizSystem::getObject($svc);		
		return call_user_method_array($method, $svcObj, $parameter);
	}    
    
	protected function _validateRequest()
	{
		$serverCode = $_REQUEST['server_code'];
		$serverRec = BizSystem::getObject($this->m_ServerDO)->fetchOne("[code]='$serverCode'");
		if(!$serverRec)
		{
			BizSystem::getService(LOG_SERVICE)->log(LOG_INFO,"AppCloudServer",'Validate Request: Unknown Server ID, Request from: '.$_SERVER['REMOTE_ADDR']);
			return false;
		}
		else		
		{
			//validate remote IP address
			if($_SERVER['REMOTE_ADDR'] != $serverRec['ipaddr'])
			{
				BizSystem::getService(LOG_SERVICE)->log(LOG_INFO,"AppCloudServer",'Validate Request: Remote IP address validate failed, Request from: '.$_SERVER['REMOTE_ADDR']);
				return false; //validate IP addr failed
			}
			
			//validate command checksum			
			if(md5($_REQUEST['server_code'].$serverRec['request_key'].$_REQUEST['rand'].$_REQUEST['method'].$_REQUEST['argsJson'])==$_REQUEST['checksum'] 
				&& $_REQUEST['checksum']!='')
			{			
				$serverId = $serverRec['Id'];
				$this->_detectedHeartbeat($serverId);
				$this->m_CurrentServerId = $serverId;
				$this->m_CurrentServerReponseKey = $serverRec['response_key'];
				return true;
			}
			else
			{
				BizSystem::getService(LOG_SERVICE)->log(LOG_INFO,"AppCloudServer",'Validate Request: Command checksum validate failed, Request from: '.$_SERVER['REMOTE_ADDR']);
				return false; //checksum failed	
			}
		}
		
	}
	
	protected function _detectedHeartbeat($serverId)
	{
		$serverRec = BizSystem::getObject($this->m_ServerDO)->fetchById($serverId);
		$serverRec['last_heartbeat'] = date('Y-m-d H:i:s');		
		$serverRec->save();
	}
}
?>